/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package automatolfa;

import java.util.ArrayList;

/**
 *
 * @author IVAN
 */
public class AnalisadorLexico {
    
    private ArrayList<Automato> _LstAutomato;
    private ArrayList<String> _LstToken;
    private String _Codigo;

    /**
     * @return the dicAutomato
     */
    public ArrayList<Automato> getLstAutomato() {
        return _LstAutomato;
    }

    /**
     * @param dicAutomato the dicAutomato to set
     */
    public void setLstAutomato(ArrayList<Automato> lstAutomato) {
        this._LstAutomato = lstAutomato;
    }

    /**
     * @return the lstToken
     */
    public ArrayList<String> getLstToken() {
        return _LstToken;
    }

    /**
     * @param lstToken the lstToken to set
     */
    public void setLstToken(ArrayList<String> lstToken) {
        this._LstToken = lstToken;
    }

    public AnalisadorLexico()
    {
        _LstAutomato = new ArrayList<Automato>();
        _LstToken = new ArrayList<String>();
    }
    
    public AnalisadorLexico(String codigo)
    {
        _Codigo = codigo;
        _LstAutomato = new ArrayList<Automato>();
        _LstToken = new ArrayList<String>();
    }

    /**
     * CRIA UM NOVO AUTOMATO NO ANALISADOR LEXICO
     * @param a - AUTOMATO
     */
    public void NovoAutomato(Automato a)
    {
        _LstAutomato.add(a);
    }

    /**
     * CRIA UM NOVO AUTOMATO NO ANALISADOR LEXICO
     * @param token - STRING COM A EXPRESSÃO DO TOKEN
     */
    public void NovoAutomato(String token, String expressao)
    {
        Automato a = new Automato(token);
        a.NovoToken(expressao);
        NovoAutomato(a);
    }

    /**
     * ANALISA UM TRECHO DE CÓDIGO
     * @param codigo - TRECHO DE CODIGO A SER ANALISADO
     * @return - "TRUE" TRECHO DE CÓDIGO VÁLIDO, "FALSE" TRECHO DE CÓDIGO INVÁLIDO
     */
    public boolean Analisar(String codigo)
    {
        _Codigo = codigo;
        return Analisar();
    }

    /**
     * ANALISA UM TRECHO DE CÓDIGO
     * @return - "TRUE" TRECHO DE CÓDIGO VÁLIDO, "FALSE" TRECHO DE CÓDIGO INVÁLIDO
     */
    public boolean Analisar()
    {
        boolean retorno = true;
        
        // Delimitadores
        ArrayList<Delimitador> lstDelimitador = new ArrayList<Delimitador>();
        lstDelimitador.add(new Delimitador("' '"));
        lstDelimitador.add(new Delimitador("ESPACO"," ", " "));
        lstDelimitador.add(new Delimitador("=="));
        lstDelimitador.add(new Delimitador("<=", "[<][=]"));
        lstDelimitador.add(new Delimitador(">=", "[>][=]"));
        lstDelimitador.add(new Delimitador("+=", "[+][=]"));
        lstDelimitador.add(new Delimitador("-=", "[-][=]"));
        lstDelimitador.add(new Delimitador("*=", "[*][=]"));
        lstDelimitador.add(new Delimitador("/=", "[/][=]"));
        lstDelimitador.add(new Delimitador("++", "[+][+]"));
        lstDelimitador.add(new Delimitador("--", "[-][-]"));
        lstDelimitador.add(new Delimitador("&&", "[&][&]"));
        lstDelimitador.add(new Delimitador("||", "[|][|]"));
        lstDelimitador.add(new Delimitador("-", "[-]"));
        lstDelimitador.add(new Delimitador("+", "[+]"));
        lstDelimitador.add(new Delimitador("="));
        lstDelimitador.add(new Delimitador("(", "[(]"));
        lstDelimitador.add(new Delimitador(")", "[)]"));
        lstDelimitador.add(new Delimitador("{", "[{]"));
        lstDelimitador.add(new Delimitador("}", "[}]"));
        lstDelimitador.add(new Delimitador(";"));
        lstDelimitador.add(new Delimitador(","));
        lstDelimitador.add(new Delimitador("<"));
        lstDelimitador.add(new Delimitador(">"));
        lstDelimitador.add(new Delimitador("/"));
        lstDelimitador.add(new Delimitador("*"));
                
        // QUEBRA O TRECHO DE CÓDIGO EM PALAVRAS A SEREM ANALISADAS COMO TOKENS OU NÃO
        ArrayList<String> tokens = AutomatoTokenizer(_Codigo, lstDelimitador);

        boolean encontrou = false;

        // PERCORRE AS PALAVRAS A SEREM ANALISADAS
        for(String tokenAtual : tokens)
        {
            encontrou = false;
            
            // PERCCORRE A LISTA DE AUTOMATOS DO ANALISADOR LEXICO
            for(Automato automato: _LstAutomato)
            {
                // VALIDA SE A PALAVRA É UM TOKEN
                if(automato.ValidaPalavra(tokenAtual))
                {
                    // ENTÃO ADICIONA À LISTA DE TOKENS
                    _LstToken.add(automato.getNome());
                    encontrou = true;
                    break;
                }
            }

            // SE NÃO ENCONTROU O TOKEN
            if(!encontrou)
            {
                _LstToken.add("Não reconhecido -> " + tokenAtual);
                // ENTÃO TRECHO DE CÓDIGO É INVÁLIDO
                retorno =  false;
            }
        }

        // TRECHO DE CÓDIGO VÁLIDO
        return retorno;
    }

    private ArrayList<String> AutomatoTokenizer(String texto, ArrayList<Delimitador> delimitadores)
    {
        ArrayList<String> tokens = new ArrayList<String>();
        
        int TamthishoDelimitador;
        int i = 0;
        boolean whileContinue;
        while(texto.length() > 0) 
        {
            whileContinue = false;
            for (Delimitador d : delimitadores)
            {
                TamthishoDelimitador = d.getValor().length();
            
                if(i+TamthishoDelimitador > texto.length())
                    continue;
                
                if(texto.substring(i, i + TamthishoDelimitador).equals(d.getValor()))
                {
                    if(i != 0)
                        tokens.add(texto.substring(0, i));
                    if(!d.getNome().equals("ESPACO"))
                        tokens.add(texto.substring(i, i + TamthishoDelimitador));
                    texto = texto.substring(i + TamthishoDelimitador);
                    i = 0;
                    whileContinue = true;
                    break;
                }
            }
            
            if(whileContinue)
                continue;
            
            i++;
            if(i == texto.length())
            {
                tokens.add(texto);
                texto = "";
            }
        }
        
        return tokens;
    }
    
    
    public void InsertAllAutomatos(){
        this.NovoAutomato("PalavraReservadaMain", "main");
        this.NovoAutomato("PalavraReservadaIf", "if");
        this.NovoAutomato("PalavraReservadaElse", "else");
        this.NovoAutomato("PalavraReservadaDo", "do");
        this.NovoAutomato("PalavraReservadaBreak", "break");
        this.NovoAutomato("OperadorIgual", "==");
        this.NovoAutomato("OperadorSubtracaoAtribuicao", "-=");
        this.NovoAutomato("OperadorSomaAtribuicao", "+=");
        this.NovoAutomato("OperadorMultiplicacaoAtribuicao", "*=");
        this.NovoAutomato("OperadorDivisaoAtribuicao", "/=");
        this.NovoAutomato("OperadorIncremento", "++");
        this.NovoAutomato("OperadorDecremento", "--");
        this.NovoAutomato("OperadorMenorIgual", "<=");
        this.NovoAutomato("OperadorMaiorIgual", ">=");
        this.NovoAutomato("PalavraReservadaWhile", "while");
        this.NovoAutomato("SimboloAbreParenteses", "(");
        this.NovoAutomato("SimboloFechaParenteses", ")");
        this.NovoAutomato("OperadorMenor", "<");
        this.NovoAutomato("OperadorMaior", ">");
        this.NovoAutomato("PalavraReservadaFor", "for");
        this.NovoAutomato("SimboloAbreChaves", "{");
        this.NovoAutomato("SimboloFechaChaves", "}");
        this.NovoAutomato("TipoInt", "int");
        this.NovoAutomato("TipoChar", "char");
        this.NovoAutomato("TipoVazio", "void");
        this.NovoAutomato("OperadorAtribuicao", "=");
        this.NovoAutomato("SimboloPontoVirgula", ";");
        this.NovoAutomato("SimboloVirgula", ",");
        this.NovoAutomato("SimboloEspaco", " ");
        this.NovoAutomato("OperadorSoma", "+");
        this.NovoAutomato("OperadorSubtracao", "-");
        this.NovoAutomato("OperadorMultiplicacao", "*");
        this.NovoAutomato("OperadorDivisao", "/");
        this.NovoAutomato("OperadorERelacional", "&&");
        this.NovoAutomato("OperadorOuRelacional", "||");
        this.NovoAutomato("OperadorRetorno", "return");
        this.NovoAutomato(Automato.AutomatoVariavel());
        this.NovoAutomato(Automato.AutomatoInteiro());
        this.NovoAutomato(Automato.AutomatoChar()); 
    }                   
    
}
